﻿using KaroglanSharedLib;
using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace KaroglanLauncher.Module
{
    internal class Updater
    {
        public string currentVersion;

        public Updater(string version)
        {
            currentVersion = version;
        }

        public bool Patch(string patchPath, bool DeleteAfterPatch)
        {
            if (!File.Exists(patchPath)) return false;
            string ver = Path.GetFileNameWithoutExtension(patchPath);
            if (!UpdateInfo.isVersionValid(ver)) return false;

            var tempFolder = Utils.GetTempFolder();
            var extractFolder = Path.Combine(tempFolder, ver);
            var backupFolder = extractFolder + "_bk";

            InitFolders();

            if (!Utils.ExtractZip(patchPath, extractFolder)) return false;
            var InfoPath = Path.Combine(extractFolder, UpdateInfo.jsonFileName);
            UpdateInfo info = UpdateInfo.Load(InfoPath);

            try
            {
                if (info == null) throw new Exception("无法加载UpdateInfo。");
                if (info.oldVersion != currentVersion) throw new Exception($"补丁版本不匹配：\n当前版本：{currentVersion}\n补丁适用：{info.oldVersion}");

                BackupModified();
                RemoveModified();
                PatchNewFiles();
            }
            catch (Exception e)
            {
                TryRevertModified();
            }
            finally
            {
                Directory.Delete(extractFolder, true);
                Directory.Delete(backupFolder, true);
                if (DeleteAfterPatch) File.Delete(patchPath);
            }

            return true;

            void TryRevertModified()
            {
                foreach (var relativePath in info.modifiedFiles)
                {
                    var srcPath = Utils.GetAbsolutePath(backupFolder, relativePath);
                    var dstPath= Utils.GetAbsolutePath(Utils.GetBaseFolder(), relativePath);
                    if (File.Exists(dstPath)) File.Delete(dstPath);

                    var dstFolder = Path.GetDirectoryName(dstPath);
                    if (!Directory.Exists(dstFolder))
                    {
                        Directory.CreateDirectory(dstFolder);
                    }
                    File.Move(srcPath, dstPath);
                }
            }

            void BackupModified()
            {
                foreach (var relativePath in info.modifiedFiles)
                {
                    var srcPath = Utils.GetAbsolutePath(Utils.GetBaseFolder(), relativePath);
                    var dstPath = Utils.GetAbsolutePath(backupFolder, relativePath);
                    if (File.Exists(srcPath)) 
                    {
                        var dstFolder = Path.GetDirectoryName(dstPath);
                        if (!Directory.Exists(dstFolder))
                        {
                            Directory.CreateDirectory(dstFolder);
                        }
                        File.Copy(srcPath, dstPath); 
                    }
                }
            }

            void RemoveModified()
            {
                foreach (var relativePath in info.modifiedFiles)
                {
                    var srcPath = Utils.GetAbsolutePath(Utils.GetBaseFolder(), relativePath);
                    File.Delete(srcPath);
                }
            }

            void PatchNewFiles()
            {
                var files = Directory.GetFiles(extractFolder,"*",SearchOption.AllDirectories);
                foreach (var path in files)
                {
                    var srcPath = path;
                    var relativePath = Utils.GetRelativePath(extractFolder, path);
                    var dstPath = Utils.GetAbsolutePath(Utils.GetBaseFolder(), relativePath);

                    var dstFolder = Path.GetDirectoryName(dstPath);
                    if (!Directory.Exists(dstFolder))
                    {
                        Directory.CreateDirectory(dstFolder);
                    }
                    if (File.Exists(dstPath)) 
                    {
                        File.Delete(dstPath);
                    }
                    File.Copy(srcPath, dstPath);
                }
            }

            void InitFolders()
            {
                if (Directory.Exists(extractFolder)) Directory.Delete(extractFolder, true);
                if (Directory.Exists(backupFolder)) Directory.Delete(backupFolder, true);
                Directory.CreateDirectory(extractFolder);
                Directory.CreateDirectory(backupFolder);
            }
        }
    }
}
